package com.example.hello.views.organizations;

import com.example.hello.*;
import com.example.hello.POJO.OrganizationPOJO;
import com.example.hello.POJO.TrackPOJO;
import com.example.hello.POJO.UserPOJO;
import com.example.hello.views.Collection;
import com.example.hello.views.tracks.Track;
import com.example.hello.views.tracks.Tracks;
import com.example.hello.views.users.Users;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.VerticalLayout;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashSet;
import java.util.Set;

public class Organization extends Collection {

    private static UserPOJO currentUser;
    private Set<TrackPOJO> tracks;
    private Set<UserPOJO> admins;
    private Set<UserPOJO> users;

    private VerticalLayout addLayout = new VerticalLayout();
    private HorizontalLayout viewLayout = new HorizontalLayout();
    private BootstrapButton back = new BootstrapButton("Back");

    private HorizontalLayout add = new HorizontalLayout();

    private StringWrap selectedTrack = new StringWrap();
    private StringWrap selectedAdmin = new StringWrap();
    private StringWrap selectedUser = new StringWrap();

    private OrganizationPOJO org;

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
//        tracks = Tracks.GETTracks("?org=" + org.getEncodedName());
//        if (tracks == null) tracks = new HashSet<>();
//        admins = Users.GETUsers("?assignedOrg=" + org.getEncodedName());
//        if (admins == null) admins = new HashSet<>();
//        users = Users.GETUsers("?org=" + org.getEncodedName());
//        if (users == null) users = new HashSet<>();

        add.setVisible(currentUser.getRole(org).ordinal() >= 2);
    }

    public Organization(String NAME, OrganizationPOJO org) {
        super(NAME);
        this.org = org;

        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
        tracks = Tracks.GETTracks("?org=" + org.getEncodedName());
        if (tracks == null) tracks = new HashSet<>();
        admins = Users.GETUsers("?assignedOrg=" + org.getEncodedName());
        if (admins == null) admins = new HashSet<>();
        users = Users.GETUsers("?org=" + org.getEncodedName());
        if (users == null) users = new HashSet<>();

        initOrganization();

        addComponents(addLayout, viewLayout, back);
        setComponentAlignment(viewLayout, Alignment.TOP_CENTER);
        setExpandRatio(viewLayout, 1);
    }

    public void initOrganization() {
        add.setWidth("800px");

        final Heading nameHeading = new Heading("Name", 6);
        final TextField nameField = new TextField();
        final BootstrapButton trackSubmit = new BootstrapButton("Add Track");
        trackSubmit.setWidth("120px");

        trackSubmit.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                addTrack(org, new TrackPOJO(nameField.getEncodedValue()), true);
                refreshView(org);
            }
        });
        TextField.enterKeyHandler(trackSubmit, nameField);

        back.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                getUI().getNavigator().navigateTo(Organizations.NAME);
            }
        });

        add.addComponents(
                nameHeading, new HSpacer(5), nameField,
                new HSpacer(20),
                trackSubmit
        );

        add.setComponentAlignment(nameHeading, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(nameField, Alignment.MIDDLE_LEFT);
        add.setExpandRatio(nameField, 1);

        addLayout.addComponents(new VSpacer(10), add, new VSpacer(20));
        addLayout.setComponentAlignment(add, Alignment.MIDDLE_CENTER);

        // add trackList for display
        viewLayout.addComponents(
                displayListBox(tracks, Tracks.NAME, selectedTrack, false, true),
                new HSpacer(40),
                displayListBox(admins, Users.NAME, selectedAdmin, false, true),
                new HSpacer(40),
                displayListBox(users, Users.NAME, selectedUser, false, true)
        );
    }

    /**
     * These static methods are intended to be used as an alternative to the HttpRequest class
     * directly. The GET(String get) method can technically return any value type, however this
     * is useful if the user of this methods knows the type of the value that should be returned.
     *
     * These methods currently reside in this View due to this View's name relationship with
     * these methods function. It might be a good idea to move these methods elsewhere later
     * (perhaps in a helper class whose sole purpose is to return the proper POJO).
     */
    public static OrganizationPOJO GET(String get) {
        OrganizationPOJO org = new OrganizationPOJO();
        try {
            String json = HttpRequest.GET(get);
            ObjectMapper mapper = new ObjectMapper();
            org = mapper.readValue(json, new TypeReference<OrganizationPOJO>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return org;
    }

    public static OrganizationPOJO GETOrg(String orgName) {
        OrganizationPOJO org = new OrganizationPOJO();
        try {
            String json = HttpRequest.GET(Organizations.NAME + "/" + orgName);
            ObjectMapper mapper = new ObjectMapper();
            org = mapper.readValue(json, new TypeReference<OrganizationPOJO>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return org;
    }

    /**
     * This method is intended to be called after changes have been made to the resource
     * associated with this View. Since the View is persistent due to its initialization
     * (unlike Users, Organizations, etc.), a new View must be created to reflect any changes.
     */
    private static void refreshView(OrganizationPOJO org) {
        HelloUI.getCurrent().getNavigator().removeView(Organizations.NAME + "/" + org.getEncodedName());
        Organization newView = new Organization(org.getEncodedName(), org);
        HelloUI.getCurrent().getNavigator().addView(newView.NAME, newView);
        HelloUI.getCurrent().getNavigator().navigateTo(newView.NAME);
    }

    /**
     * The methods below are intended to provide the proper JOIN mechanism between
     * related resources.
     */
    public static boolean addAdmin(OrganizationPOJO org, UserPOJO admin, boolean create) {
        org.addAdmin(admin.getEncodedName());
        admin.addAssignedOrg(org.getEncodedName());
        return org.update() && (create ? admin.create() : admin.update());
    }

    public static boolean removeAdmin(OrganizationPOJO org, UserPOJO admin) {
        org.removeAdmin(admin.getEncodedName());
        admin.removeAssignedOrg(org.getEncodedName());
        return org.update() && admin.update();
    }

    public static boolean addTrack(OrganizationPOJO org, TrackPOJO track, boolean create) {
        org.addTrack(track.getEncodedName());
        track.setOrganization(org.getEncodedName());
        return org.update() && (create ? track.create() : track.update());
    }

    public static boolean removeTrack(OrganizationPOJO org, TrackPOJO track) {
        org.removeTrack(track.getEncodedName());
        track.setOrganization(TrackPOJO.UNASSIGNED);
        return org.update() && track.update();
    }

    public static boolean addUser(OrganizationPOJO org, UserPOJO user, boolean create) {
        org.addUser(user.getEncodedName());
        user.addOrg(org.getEncodedName());
        return org.update() && (create ? user.create() : user.update());
    }

    public static boolean removeUser(OrganizationPOJO org, UserPOJO user) {
        org.removeUser(user.getEncodedName());
        user.removeOrg(org.getEncodedName());
        return org.update() && user.update();
    }

}